﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DTO;
using System.Collections;

namespace BLL
{
    public class Crossovers
    {

        public void orderCrossover(PathTour Par1, PathTour par2, out PathTour child1, out PathTour child2, Random ran)
        {
            int numCity = Par1.OrderCity.Length;
            child1 = new PathTour(numCity);
            child2 = new PathTour(numCity);
            int pos1 = ran.Next(numCity - 1);
            int pos2 = ran.Next(numCity - pos1) + pos1;

            ArrayList s1 = new ArrayList();
            ArrayList s2 = new ArrayList();
            for (int i = pos1; i <= pos2; i++)
            {
                child1.OrderCity[i] = Par1.OrderCity[i];
                s1.Add(Par1.OrderCity[i]);
                child2.OrderCity[i] = par2.OrderCity[i];
                s2.Add(par2.OrderCity[i]);
            }
            int index1 = 1;
            int index2 = 1;
            int temp = 0;
            for (int i = 1; i <= numCity; i++) //for (int i = pos2+1; i < pos2 + this.chromoLength - (pos2 - pos1 + 1); i++)
            {
                temp = i + pos2;
                if (temp >= numCity)
                {
                    temp = temp - numCity;
                }
                int ps1 = index1 + pos2;
                if (ps1 >= numCity)
                {
                    ps1 = ps1 - numCity;
                }
                int ps2 = index2 + pos2;
                if (ps2 >= numCity)
                {
                    ps2 = ps2 - numCity;
                }
                if (!s1.Contains(par2.OrderCity[temp]))
                {
                    child1.OrderCity[ps1] = par2.OrderCity[temp];
                    index1++;
                }
                if (!s2.Contains(Par1.OrderCity[temp]))
                {
                    child2.OrderCity[ps2] = Par1.OrderCity[temp];
                    index2++;
                }
            }          
        }


        #region Crossover use path representation

            private int findNextCity(int city, int[] tour, int numOfCity)
            {
                int t = 0;
                for (int i = 0; i < numOfCity; i++)
                {
                    if (tour[i] == city)
                    {
                        if (i == numOfCity - 1)
                        {
                            break;
                        }
                        else
                        {
                            t = tour[i + 1];
                            break;
                        }
                    }
                }
                return t;
            }

            //method find city if next city is visited. Radius for finding is r
            private int findCity_Radius(int currentCity, int[] parentTour, int numOfCity, bool[] visitedCity, int radius, CityObject[] coor)
            {
                int minCt = -1;
                double minDistance = float.MaxValue;
                double tempDis;

                int incRadius = 0;
                Evaluate calDistance = new Evaluate();
                for (int j = 0; j < numOfCity; j++)
                {
                    if (!visitedCity[parentTour[j] - 1])
                    {
                        incRadius++;
                        tempDis = calDistance.calculateDistance(currentCity - 1, parentTour[j] - 1, coor);
                        if (tempDis < minDistance)                
                        {
                            minDistance = tempDis;
                            minCt = parentTour[j];
                        }
                        if (incRadius == radius)
                        {
                            break;
                        }
                    }
                }
                return minCt;
            }

            //MSCX For path representation
            public void MSCX(PathTour Par1, PathTour Par2, out PathTour child, int numOfCity, CityObject[] coor, Random ran)
            {
                bool[] bit = new bool[numOfCity];
                int nextCt1, nextCt2;

                for (int i = 0; i < numOfCity; i++)
                {
                    bit[i] = false;
                }

                child = new PathTour(numOfCity);
                child.OrderCity[0] = Par1.OrderCity[0];
                bit[child.OrderCity[0] - 1] = true;

                int idxCity = -1;
                for (int i = 1; i < numOfCity; i++)
                {
                    nextCt1 = findNextCity(child.OrderCity[i - 1], Par1.OrderCity, numOfCity);
                    if (nextCt1 == 0 || bit[nextCt1 - 1])
                    {
                        for (int j = 0; j < numOfCity; j++)
                        {
                            if (!bit[Par1.OrderCity[j] - 1])
                            {
                                idxCity = j;
                                break;
                            }
                        }
                        nextCt1 = Par1.OrderCity[idxCity];
                    }

                    nextCt2 = findNextCity(child.OrderCity[i - 1], Par2.OrderCity, numOfCity);
                    //if nextCt2 == 0
                    if (nextCt2 == 0 || bit[nextCt2 - 1])
                    {
                        for (int j = 0; j < numOfCity; j++)
                        {
                            if (!bit[Par2.OrderCity[j] - 1])
                            {
                                idxCity = j;
                                break;
                            }
                        }
                        nextCt2 = Par2.OrderCity[idxCity];
                    }
                    Evaluate calDistance = new Evaluate();
                    if (calDistance.calculateDistance(child.OrderCity[i - 1] - 1, nextCt1 - 1, coor) < calDistance.calculateDistance(child.OrderCity[i - 1] - 1, nextCt2 - 1, coor))
                    {
                        child.OrderCity[i] = nextCt1;
                        bit[nextCt1 - 1] = true;
                    }
                    else
                    {
                        child.OrderCity[i] = nextCt2;
                        bit[nextCt2 - 1] = true;
                    }
                }//for
            }//method
            
            //Cross use random gen from two parents
            //num_random is input parameter, which determine the number of cities are gotten for children
            public void CRD(int num_random, PathTour Par1, PathTour Par2, out PathTour child1, out PathTour child2,  int numOfCity, CityObject[] coor, Random ran)
            {
                bool[] bit1 = new bool[numOfCity];
                bool[] bit2 = new bool[numOfCity];
                int idx1, idx2;              
                for (int i = 0; i < numOfCity; i++)
                {
                    bit1[i] = true;
                    bit2[i] = true;
                }
                child1 = new PathTour(numOfCity);
                child2 = new PathTour(numOfCity);
                int idxCity = -1;
                for (int i = 0; i < num_random; i++)
                {
                    do 
                    {
                        idxCity = Par2.OrderCity[ran.Next(numOfCity)];
                    } while (!bit1[idxCity - 1]);
                    child1.OrderCity[i] = idxCity;
                    bit1[idxCity - 1] = false;
                    do
                    {
                        idxCity = Par1.OrderCity[ran.Next(numOfCity)];
                    } while (!bit2[idxCity - 1]);
                    child2.OrderCity[i] = idxCity;
                    bit2[idxCity - 1] = false;
                }
                idx1 = num_random;
                idx2 = num_random;
                for (int i = 0; i < numOfCity; i++)
                {
                    idxCity = Par1.OrderCity[i];
                    if (bit1[idxCity - 1])
                    {
                        child1.OrderCity[idx1] = idxCity;
                        bit1[idxCity - 1] = false;
                        idx1++;
                    }
                    idxCity = Par2.OrderCity[i];
                    if (bit2[idxCity - 1])
                    {
                        child2.OrderCity[idx2] = idxCity;
                        bit2[idxCity - 1] = false;
                        idx2++;
                    }                  
                }//for
            }//method
            
          
        #endregion

    }
}
